#include "SerialManage.h"
#include <QSerialPortInfo>
#include <QDebug>
#include "MsgParser.h"
#include "deviceType.h"
#include "mylogger.h"
#include "gtime.h"
#include <QSettings>
#include "networkmanage.h"

using namespace ns_yht;

SerialManage *SerialManage::g_instance = nullptr;

SerialManage::SerialManage(QObject *parent) : PortManage(parent)
{
}

SerialManage::~SerialManage()
{
    foreach (auto port, m_portList)
    {
        port->setDataTerminalReady(false);
        port->close();
        port->deleteLater();
    }
}

SerialManage *SerialManage::instance()
{
    if (!g_instance)
        g_instance = new SerialManage();
    return g_instance;
}

QSerialPort *SerialManage::getPort(const QString &portName) const
{
    if (m_portList.contains(portName))
        return m_portList[portName];
    else
        return nullptr;
}

bool SerialManage::openPort(const QString &portName, qint32 baudRate, bool bdPort)
{
    QSerialPort *port;
    if (m_portList.contains(portName))
        port = m_portList[portName];
    else
    {
        port = new QSerialPort;
        m_portList[portName] = port;
        connect(port, &QSerialPort::readyRead, this, &SerialManage::onReadyRead);
    }

    port->setPortName(portName);
    port->setBaudRate(baudRate);
    //    port->setDataBits(QSerialPort::DataBits(m_cmbBits->currentData().toUInt()));
    //    port->setParity(QSerialPort::Parity(m_cmbParity->currentData().toUInt()));
    //    port->setStopBits(QSerialPort::StopBits(m_cmbStop->currentData().toUInt()));
    //    port->setFlowControl(QSerialPort::FlowControl(m_cmbFlowControl->currentData().toUInt()));

    QIODevice::OpenMode om = bdPort ? QIODevice::ReadWrite : QIODevice::ReadOnly;

    if (port->open(om))
    {
        if (bdPort)
            m_bdPort = portName;
        if (GLOG)
            GLOG->info("serialport open succeed!  {},{}", portName.toStdString(), baudRate);
        emit portStateChanged(portName, true);
        return true;
    }
    else
    {
        if (GLOG)
            GLOG->info("serialport open failed!  {},{}", portName.toStdString(), baudRate);
        return false;
    }
}

void SerialManage::closePort(const QString &portName)
{
    QSerialPort *port = m_portList[portName];
    if (port)
    {
        port->close();
        emit portStateChanged(portName, false);
    }
}

void SerialManage::onReadyRead()
{
    QSerialPort *serialPort = qobject_cast<QSerialPort *>(sender());
    if (!serialPort)
        return;
    if (serialPort->bytesAvailable())
    {
        m_buffer = serialPort->readAll();
        m_msgQueue.enqueue(m_buffer);
        if (GLOG_AIS)
            GLOG_AIS->info(m_buffer);
    }
}

QString SerialManage::getPortsSetting() const
{
    QString s;
    const QChar sep(0x1E);
    for (auto it = m_portList.begin(); it != m_portList.end(); ++it)
    {
        if (!it.value()->isOpen())
            continue;
        if (s != "")
            s += sep;
        s = s.append(QString("%1|%2").arg(it.key()).arg(it.value()->baudRate()));
    }

    return s;
}

void SerialManage::setPortsSetting(const QString &portsSetting)
{
    const QChar sep(0x1E);
    QVector<QStringRef> ss = portsSetting.splitRef(sep);

    foreach (auto s2, ss)
    {
        QVector<QStringRef> s2s = s2.split('|');
        QString portName;
        int baudRate;
        int n = s2s.count();
        if (n != 2)
            continue;

        portName = s2s.first().toString();
        baudRate = s2s.last().toInt();

        if (openPort(portName, baudRate, false))
        {
            // if (GLOG)
            // GLOG->info("[{}] open ok!", portName.toStdString());
        }
        // else if (GLOG)
        //     GLOG->info("[{}] open failed!", portName.toStdString());
    }
}

void SerialManage::moveToThreadEx(QThread *thread)
{
    foreach (auto port, m_portList)
        port->moveToThread(thread);
    PortManage::moveToThreadEx(thread);
}

void SerialManage::sendBDMessage(const QByteArray &msg)
{
    QSerialPort *port = getPort(m_bdPort);
    if (port && port->isOpen())
        port->write(msg);
}

QString SerialManage::getBdPort() const
{
    return m_bdPort;
}